package com.heima.wemedia.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.file.service.FileStorageService;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.dtos.WmMaterialDto;
import com.heima.model.wemedia.pojos.WmMaterial;
import com.heima.model.wemedia.pojos.WmNewsMaterial;
import com.heima.utils.thread.WmThreadLocalUtil;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.service.WmMaterialService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.UUID;


@Slf4j
@Service
@Transactional
public class WmMaterialServiceImpl extends ServiceImpl<WmMaterialMapper, WmMaterial> implements WmMaterialService {

	@Autowired
	private FileStorageService fileStorageService;

	@Autowired
	private WmNewsMaterialMapper wmNewsMaterialMapper;

	@Autowired
	private WmMaterialMapper wmMaterialMapper;


	/**
	 * 上传图片接口
	 *
	 * @param multipartFile，这个参数的前端传递的默认参数名，别取其他名字
	 * @return
	 */
	@Override
	public ResponseResult uploadPicture(MultipartFile multipartFile) {
		//1.检查参数,判断multipartFile是否为空，以及是否大小为0
		if (multipartFile == null || multipartFile.getSize() == 0) {
			//如果multipartFile为空或为0，直接提示参数无效
			return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
		}
		//2.上传图片到minio中,这里需要将自媒体模块集成minio技术
		//文件上传到minio中，需要给名称取一个新名字，避免数据覆盖，这里用UUID来生成随机名
		//首先通过UUID生成一个随机名字
		String fileName = UUID.randomUUID().toString().replace("-", "");
		//这里通过multipartFile获取文件的原始名字
		String originalFilename = multipartFile.getOriginalFilename();
		//这里通过截取的方式，取得元素名后面的名字，即假如有图片叫abc.jpg,这里是取出".jpg"这部分，放在UUID生成的字符串后面，就是新名字
		String postfix = originalFilename.substring(originalFilename.lastIndexOf("."));
		String fileId = null;//这里定义了一个字符串fileId，定义在外面，则为全局变量
		try {
			//这里调用上传图片接口，将图片以新名字上传到minio中存储，这里会将图片名字的id记录下来,fileId即为图片名字
			fileId = fileStorageService.uploadImgFile("", fileName + postfix, multipartFile.getInputStream());
			log.info("上传图片到minio中，fileId：{}", fileId);
		} catch (IOException e) {
			//如果出现异常，则提示文件上传失败
			e.printStackTrace();
			log.info("WmMaterialServiceImpl上传文件失败");
		}
		//3.保存到数据库中
		WmMaterial wmMaterial = new WmMaterial();//创建一个新的WmMaterial对象
		wmMaterial.setUserId(WmThreadLocalUtil.getUser().getId());//如果threadlocal获取用户id，设置图片用户id
		wmMaterial.setUrl(fileId);//设置图片路径
		wmMaterial.setIsCollection((short) 0);//设置是否被收藏，默认没有被收藏
		wmMaterial.setType((short) 0);//设置图片类型，0表示图片
		wmMaterial.setCreatedTime(new Date());//设置创建时间
		save(wmMaterial);//调用mp的save将新对象保存到数据库中
		//4.返回结果
		return ResponseResult.okResult(wmMaterial);
	}

	/**
	 * 素材列表查询，根据传入的参数查询用户上传的素材列表，并返回分页结果
	 *
	 * @param dto
	 * @return
	 */
	@Override
	public ResponseResult findList(WmMaterialDto dto) {

		//1.检查参数，这是调用了PageRequestDto的checkParam方法，检查参数是否为空
		//如果参数为空，则将参数设置为默认值
		dto.checkParam();

		//2.分页查询,创建一个 IPage 对象 page，用于存储分页查询结果
		//Page 类是 MyBatis-Plus 提供的一个分页类，dto.getPage() 和 dto.getSize() 分别对应前端请求的页码和每页显示的记录数
		IPage page = new Page(dto.getPage(), dto.getSize());
		//3.查询条件，这里使用了 LambdaQueryWrapper 来构造查询条件
		LambdaQueryWrapper<WmMaterial> lambdaQueryWrapper = new LambdaQueryWrapper<>();
		//是否收藏
		if (dto.getIsCollection() != null && dto.getIsCollection() == 1) {
			//如果是1，则表示只查询收藏的
			lambdaQueryWrapper.eq(WmMaterial::getIsCollection, dto.getIsCollection());
		}

		//按照用户查询,这里使用了 LambdaQueryWrapper 来构造查询条件
		lambdaQueryWrapper.eq(WmMaterial::getUserId, WmThreadLocalUtil.getUser().getId());

		//按照时间倒序,这里使用了 LambdaQueryWrapper 来构造查询条件
		lambdaQueryWrapper.orderByDesc(WmMaterial::getCreatedTime);

		//4.分页查询
		page = page(page, lambdaQueryWrapper);

		//3.结果返回
		ResponseResult responseResult = new PageResponseResult(dto.getPage(), dto.getSize(), (int) page.getTotal());
		responseResult.setData(page.getRecords());
		return responseResult;
	}

	/**
	 * 素材图片删除
	 *
	 * @param id
	 * @return
	 */
	@Override
	public ResponseResult delPicture(Integer id) {
		//参数校验
		if (id == null) {
			//如果id为空，则提示参数无效
			return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
		}

		//判断素材是否存在
		//通过WmMaterialMapper的selectById方法根据传入的id查询对应的图片素材
		WmMaterial wmMaterial = wmMaterialMapper.selectById(id);
		//如果查询结果为空，则提示素材不存在
		if (wmMaterial == null) {
			//如果查询结果为空，则提示素材不存在
			return ResponseResult.errorResult(AppHttpCodeEnum.AP_USER_DATA_NOT_EXIST);
		}

		//判断该素材是否被引用，如果是，则返回删除失败
		List<WmNewsMaterial> wmNewsMaterials = wmNewsMaterialMapper.selectList(Wrappers.<WmNewsMaterial>lambdaQuery()
				.eq(WmNewsMaterial::getMaterialId, id));
		if (wmNewsMaterials != null && wmNewsMaterials.size() != 0) {
			return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "文件删除失败");
		}

		//成功删除 同时删除minio中的文件
		fileStorageService.delete(wmMaterial.getUrl());
		removeById(id);
		return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
	}


	/**
	 * 收藏或取消收藏
	 *
	 * @param id
	 * @return
	 */
	@Override
	public ResponseResult collectOrCancel(Integer id) {
		//参数校验，判断id是否为空，如果为空，则提示参数无效
		if (id == null) {
			//如果id为空，则提示参数无效
			return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
		}

		//判断素材是否存在
		//通过WmMaterialMapper的selectById方法根据传入的id查询对应的图片素材
		WmMaterial wmMaterial = wmMaterialMapper.selectById(id);
		//如果查询结果为空，则提示素材不存在
		if (wmMaterial == null) {
			return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
		}

		if (wmMaterial.getIsCollection() == (short) 1) {
			//等于1，说明已经收藏，则取消收藏
			wmMaterial.setIsCollection((short) 0);
			updateById(wmMaterial);
			return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
		}

		//走到这里说明wmMaterial 不为空 且 idCollection == 0
		wmMaterial.setIsCollection((short) 1);
		//调用updateById方法更新数据库
		updateById(wmMaterial);
		//返回结果
		return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
	}
}
